package com.hyacinth.utils.serialize.protostuff;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

/**
 * protostuff序列化工具类
 * @author zhangfb
 * @version 1.0.0.1
 * @since JDK 1.8
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ProtostuffUtils {

    /** 获取schema缓存 **/
    private static SchemaCache schemaCache = SchemaCache.getInstance();

    private static Objenesis objenesis = new ObjenesisStd(true);

    /**
     * 根据类型获取Schema
     */
    private static <T> Schema<T> getSchema(Class<T> clazz) {
        return (Schema<T>) schemaCache.get(clazz);
    }

    /**
     * 对象->字节数组 序列化
     */
    public static <T> byte[] serialize(T obj) {
        //获得对象的类
        Class<T> clazz = (Class<T>) obj.getClass();
        //使用LinkedBuffer分配一块默认大小的buffer空间
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            //通过对象的类构建对应的schema
            Schema<T> schema = getSchema(clazz);
            //使用给定的schema将对象序列化为一个byte数组，并返回
            return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } finally {
            buffer.clear();
        }

    }

    /**
     * 字节数组->对象  反序列化
     */
    public static <T> T deserialize(byte[] data, Class<T> clazz) {
        //使用objenesis实例化一个类的对象
        T message = objenesis.newInstance(clazz);
        //通过对象的类构建对应的schema
        Schema<T> schema = getSchema(clazz);
        //使用给定的schema将byte数组和对象合并
        ProtostuffIOUtil.mergeFrom(data, message, schema);
        return message;
    }
}
